package com.jiezuo.flowable.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jiezuo.common.exception.BusinessRuntimeException;
import com.jiezuo.common.util.StringUtil;
import com.jiezuo.flowable.entity.MyFormDesign;
import com.jiezuo.flowable.entity.MyFormInformation;
import com.jiezuo.flowable.mapper.MyFormDesignMapper;
import com.jiezuo.flowable.service.MyFormDesignService;
import com.jiezuo.flowable.service.MyFormInformationService;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.FormService;
import org.flowable.engine.ProcessEngine;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.TaskService;
import org.flowable.engine.form.FormProperty;
import org.flowable.engine.form.StartFormData;
import org.flowable.engine.form.TaskFormData;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.task.api.Task;
import org.flowable.ui.modeler.domain.Model;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
 * @description 表单设计器
 * @author 庞留杰
 * @date 2024/03/06 16:49
 * @version V1.0
 **/
@Transactional
@Slf4j
@Service
public class MyFormDesignServiceImpl extends ServiceImpl<MyFormDesignMapper, MyFormDesign> implements MyFormDesignService {

    @Autowired
    ProcessEngine processEngine;
    @Autowired
    MyFormInformationService informationService;

    @Override
    public IPage<MyFormDesign> findPage(Page initMpPage, MyFormDesign myFormDesign) {
        QueryWrapper<MyFormDesign> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("is_delete", "0");
        queryWrapper.orderByDesc("created_time");
        return this.page(initMpPage, queryWrapper);
    }

    @Override
    public List<MyFormDesign> findList(MyFormDesign myFormDesign) {
        QueryWrapper<MyFormDesign> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("is_delete", "0");
        List<MyFormDesign> list = this.list(queryWrapper);
        return list;
    }

    @Override
    public MyFormDesign findById(String id) {
        return this.getById(id);
    }

    @Override
    public boolean add(MyFormDesign myFormDesign) {
        Integer version = StringUtil.isNotEmpty(myFormDesign.getVersion()) ? Integer.valueOf(myFormDesign.getVersion()) + 1 : 1;
        myFormDesign.setVersion(String.valueOf(version));
        boolean save = this.save(myFormDesign);
        if (save) {
            saveOrUpdateModel(myFormDesign);
        }
        return save;
    }

    @Override
    public boolean update(MyFormDesign myFormDesign) {
        Integer version = StringUtil.isNotEmpty(myFormDesign.getVersion()) ? Integer.valueOf(myFormDesign.getVersion()) + 1 : 1;
        myFormDesign.setVersion(String.valueOf(version));
        boolean b = this.updateById(myFormDesign);
        if (b) {
            saveOrUpdateModel(myFormDesign);
        }
        return b;
    }


    private static final String NAMESPACE = "org.flowable.ui.modeler.domain.Model.";
    @Autowired
    protected SqlSessionTemplate sqlSessionTemplate;

    //添加或更新act_de_model中数据
    Model saveOrUpdateModel(MyFormDesign myFormDesign) {
        Model m = new Model();
        m.setId(myFormDesign.getId());
        m.setName(myFormDesign.getName());
        m.setKey(myFormDesign.getCode());
        m.setDescription(myFormDesign.getNote());
        m.setCreated(myFormDesign.getCreated_time());
        m.setLastUpdated(myFormDesign.getUpdated_time());
        m.setCreatedBy(myFormDesign.getCreated_by());
        m.setLastUpdatedBy(myFormDesign.getUpdated_by());
        m.setVersion(Integer.valueOf(myFormDesign.getVersion()));
        //{"name":"请假申请表单","key":"qingjia","version":0,"fields":[{"fieldType":"FormField","id":"请假申请单id","name":"请假申请单","type":"headline","value":null,"required":false,"readOnly":false,"overrideId":true,"placeholder":null,"layout":null},{"fieldType":"FormField","id":"请假日期id","name":"请假日期","type":"date","value":null,"required":false,"readOnly":false,"overrideId":true,"placeholder":null,"layout":null},{"fieldType":"FormField","id":"请假事由Id","name":"请假事由","type":"multi-line-text","value":null,"required":false,"readOnly":false,"overrideId":true,"placeholder":null,"layout":null}],"outcomes":[]}
        m.setModelEditorJson("{}");
        m.setComment(null);
        m.setModelType(2);//表单
        m.setTenantId(null);
        Object o = sqlSessionTemplate.selectOne(NAMESPACE + "selectModel", myFormDesign.getId());
        if (o == null) {//新增
            int insert = sqlSessionTemplate.insert(NAMESPACE + "insertModel", m);
            System.out.println("新增act_de_model数据:" + (insert > 0 ? "成功" : "失败"));
        } else {//编辑
            int update = sqlSessionTemplate.update(NAMESPACE + "updateModel", m);
            System.out.println("编辑act_de_model数据:" + (update > 0 ? "成功" : "失败"));
        }
        return m;
    }

    @Override
    public boolean delete(String id) {
        MyFormDesign myFormDesign = new MyFormDesign();
        myFormDesign.setId(id);
        myFormDesign.setIs_delete("1");
        return this.updateById(myFormDesign);
    }

    @Override
    public JSONArray findPropertiesById(String id) {
        MyFormDesign byId = this.getById(id);
        String content = byId.getContent();
        JSONObject object = JSON.parseObject(content);
        JSONArray widgetList = object.getJSONArray("widgetList");
        JSONArray properties = new JSONArray();
        System.out.println("widgetList = " + widgetList);
        for (int i = 0; i < widgetList.size(); i++) {
            JSONObject widget = (JSONObject) widgetList.get(i);
            JSONObject options = (JSONObject) widget.get("options");
            String formFiledType = String.valueOf(widget.get("type"));
            /*
                FLOWABLE流程中类型：string  long   boolean  date enum
                VFORM中类型：
                    单行输入	input      ------------ string
                    多行输入	textarea   ------------ string
                    计数器	number     ------------ long
                    单选项	radio      ------------ long
                    多选项	checkbox   ------------ enum
                    下拉选项	select     ------------ enum
                    时间	time       ------------ date
                    时间范围	time-range ------------ date
                    日期	date       ------------ date
                    日期范围	date-range ------------ date
                    开关	switch     ------------ boolean
                    评分	rate       ------------ long
                    颜色选择器	color  ------------ string
                    滑块	slider     ------------ long
                    静态文字	static-text------------ string
                    HTML	html-text  ------------ string
                    按钮	button     ------------ string
                    分隔线	divider    ------------ string
                    图片	picture-upload----------string
                    文件	file-upload ------------string
                    富文本	rich-editor ------------string
                    级联选择	cascader   ------------ string
            */
            /*String type = "string";
            String[] STRING_ARRAY = new String[]{"input", "textarea", "color", "static-text", "html-text",
                    "button", "divider", "picture-upload", "file-upload", "rich-editor", "cascader"};
            String[] LONG_ARRAY = new String[]{"number", "rate", "slider", "radio"};
            String[] BOOLEAN_ARRAY = new String[]{"switch"};
            String[] DATE_ARRAY = new String[]{"time", "time-range", "date", "date-range"};
            String[] ENUM_ARRAY = new String[]{"select", "checkbox"};
            if (Arrays.asList(STRING_ARRAY).contains(o1.get("type"))) {
                type = "string";
            } else if (Arrays.asList(LONG_ARRAY).contains(o1.get("type"))) {
                type = "long";
            } else if (Arrays.asList(BOOLEAN_ARRAY).contains(o1.get("type"))) {
                type = "boolean";
            } else if (Arrays.asList(DATE_ARRAY).contains(o1.get("type"))) {
                type = "date";
            } else if (Arrays.asList(ENUM_ARRAY).contains(o1.get("type"))) {
                type = "enum";
            }*/
            String type = "string";// 目前全部转为字符串
            if ("vf-dialog".equals(formFiledType)) {//表单
                //表单，暂不处理
            } else if ("data-table".equals(formFiledType)) {//数据表格
                JSONObject obj = new JSONObject();
                obj.put("type", type);//类型全部未默认值
                obj.put("name", options.get("name"));
                obj.put("label", options.get("label"));
                properties.add(obj);
            } else if ("grid".equals(formFiledType)) {//栅格
                JSONArray cols = widget.getJSONArray("cols");
                if (cols != null) {
                    for (int x = 0; x < cols.size(); x++) {
                        JSONObject col = (JSONObject) cols.get(x);
                        JSONArray childrenWidgetList = col.getJSONArray("widgetList");
                        if (childrenWidgetList != null) {
                            for (int j = 0; j < childrenWidgetList.size(); j++) {
                                JSONObject childrenWidget = (JSONObject) childrenWidgetList.get(j);
                                JSONObject childrenOptions = (JSONObject) childrenWidget.get("options");
                                JSONObject obj = new JSONObject();
                                obj.put("type", type);//类型全部未默认值
                                obj.put("name", childrenOptions.get("name"));
                                obj.put("label", childrenOptions.get("label"));
                                properties.add(obj);
                            }
                        }
                    }
                }
                // } else if ("sub-form".equals(formFiledType)) {//子表单 (只获取最外层的属性即可，对内层属性暂时不做控制，否则设置太复杂)
            } else {
                JSONObject obj = new JSONObject();
                obj.put("type", type);//类型全部未默认值
                obj.put("name", options.get("name"));
                obj.put("label", options.get("label"));
                properties.add(obj);
            }
        }
        return properties;
    }

    @Override
    public JSONObject findFormByKey(String processDefinitionKey, String businessId) {
        RepositoryService repositoryService = processEngine.getRepositoryService();
        FormService formService = processEngine.getFormService();
        List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery()
                .processDefinitionKey(processDefinitionKey).orderByProcessDefinitionVersion().desc().list();
        if (list.size() == 0) {
            throw new BusinessRuntimeException("流程尚未发布，请检查...");
        }
        ProcessDefinition definition = list.get(0);
        String processDefinitionId = definition.getId();
        StartFormData formData = formService.getStartFormData(processDefinitionId);
        String formKey = formData.getFormKey();//表单key
        List<FormProperty> formProperties = formData.getFormProperties();//流程中的表单属性
        JSONObject result = new JSONObject();
        if (StringUtil.isNotEmpty(businessId)) {
            QueryWrapper<MyFormInformation> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("code", formKey);
            queryWrapper.eq("business_id", businessId);
            queryWrapper.eq("is_delete", "0");
            queryWrapper.orderByDesc("updated_time");
            List<MyFormInformation> forms = informationService.list(queryWrapper);
            String content = "";
            if (forms.size() > 0) {
                MyFormInformation information = forms.get(0);
                result.put("formKey", formKey);
                result.put("informationId", information.getId());
                result.put("data", information.getData());
                content = information.getContent();
                content = contentProcess(formProperties, content);
                result.put("content", content);
            }
        } else {
            // 查询表单信息
            QueryWrapper<MyFormDesign> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("is_delete", "0");
            queryWrapper.eq("code", formKey);
            List<MyFormDesign> formList = this.list(queryWrapper);
            String content = "";
            if (formList.size() > 0) {
                MyFormDesign myFormDesign = formList.get(0);
                content = myFormDesign.getContent();
                content = contentProcess(formProperties, content);
            }
            result.put("formKey", formKey);
            result.put("content", content);
        }
        return result;
    }

    @Override
    public JSONObject findFormByTaskId(String taskId) {
        FormService formService = processEngine.getFormService();
        TaskService taskService = processEngine.getTaskService();
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if (task == null) {
            log.error("taskId：{} 查询不到数据...", taskId);
            throw new BusinessRuntimeException("当前数据可能已被执行，请刷新...");
        }
        TaskFormData formData = formService.getTaskFormData(taskId);
        String processInstanceId = task.getProcessInstanceId();
        String formKey = formData.getFormKey();
        List<FormProperty> formProperties = formData.getFormProperties();//流程中的表单属性
        // 查询表单信息
        QueryWrapper<MyFormInformation> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("is_delete", "0");
        queryWrapper.eq("process_instance_id", processInstanceId);
        List<MyFormInformation> formList = informationService.list(queryWrapper);
        String content = "", data = "", informationId = "";
        if (formList.size() > 0) {
            MyFormInformation information = formList.get(0);
            content = information.getContent();
            informationId = information.getId();
            data = information.getData();
            content = contentProcess(formProperties, content);
        }
        JSONObject result = new JSONObject();
        result.put("formKey", formKey);
        result.put("informationId", informationId);
        result.put("data", data);
        result.put("content", content);
        return result;
    }

    @Override
    public JSONObject findFormByProcessInstanceId(String processInstanceId) {
        QueryWrapper<MyFormInformation> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("process_instance_id", processInstanceId);
        queryWrapper.eq("is_delete", "0");
        MyFormInformation one = informationService.getOne(queryWrapper);
        JSONObject result = new JSONObject();
        result.put("formKey", one.getCode());
        result.put("informationId", null);
        result.put("data", one.getData());
        result.put("content", one.getContent());
        return result;
    }

    @Override
    public JSONObject findFormByBusinessId(String code, String business_id) {
        QueryWrapper<MyFormInformation> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("code", code);
        queryWrapper.eq("business_id", business_id);
        queryWrapper.eq("is_delete", "0");
        MyFormInformation one = informationService.getOne(queryWrapper);
        JSONObject result = new JSONObject();
        result.put("formKey", one.getCode());
        result.put("informationId", null);
        result.put("data", one.getData());
        result.put("content", one.getContent());
        return result;
    }

    @Override
    public Boolean findFormIsExistByProcessInstanceId(String processInstanceId) {
        QueryWrapper<MyFormInformation> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("process_instance_id", processInstanceId);
        queryWrapper.eq("is_delete", "0");
        MyFormInformation one = informationService.getOne(queryWrapper);
        return one == null ? false : true;
    }

    @Override
    public Boolean findFormIsExistByBusinessId(String code, String business_id) {
        QueryWrapper<MyFormInformation> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("code", code);
        queryWrapper.eq("business_id", business_id);
        queryWrapper.eq("is_delete", "0");
        MyFormInformation one = informationService.getOne(queryWrapper);
        return one == null ? false : true;
    }

    // 对表单内容进行解析
    private String contentProcess(List<FormProperty> formProperties, String content) {
        JSONObject object = JSON.parseObject(content);
        JSONArray widgetList = object.getJSONArray("widgetList");
        for (int i = 0; i < widgetList.size(); i++) {
            JSONObject widget = widgetList.getJSONObject(i);
            JSONObject options = widget.getJSONObject("options");
            String formFiledType = String.valueOf(widget.get("type"));
            if ("vf-dialog".equals(formFiledType)) {//表单
                //表单，暂不处理
            } else if ("data-table".equals(formFiledType)) {//数据表格
                JSONArray cols = widget.getJSONArray("cols");
                if (cols != null) {// 栅格
                    // 暂时不处理
                } else {
                    options(formProperties, options);
                }
            } else if ("grid".equals(formFiledType)) {//栅格
                JSONArray cols = widget.getJSONArray("cols");
                if (cols != null) {
                    for (int x = 0; x < cols.size(); x++) {
                        JSONObject col = (JSONObject) cols.get(x);
                        JSONArray childrenWidgetList = col.getJSONArray("widgetList");
                        if (childrenWidgetList != null) {
                            for (int j = 0; j < childrenWidgetList.size(); j++) {
                                JSONObject childrenWidget = (JSONObject) childrenWidgetList.get(j);
                                JSONObject childrenOptions = (JSONObject) childrenWidget.get("options");
                                String type = String.valueOf(childrenWidget.get("type"));
                                if ("sub-form".equals(type)) {
                                    JSONArray childrenWidgetLists = childrenWidget.getJSONArray("widgetList");
                                    subFormOptions(formProperties, childrenOptions, childrenWidgetLists);
                                } else {
                                    options(formProperties, childrenOptions);
                                }
                            }
                        }
                    }
                }
            } else if ("sub-form".equals(formFiledType)) {//子表单
                JSONArray widgetLists = widget.getJSONArray("widgetList");
                subFormOptions(formProperties, options, widgetLists);
            } else {
                options(formProperties, options);
            }
        }
        return JSON.toJSONString(object);
    }

    // 对表单字段进行控制
    void options(List<FormProperty> formProperties, JSONObject options) {
        Optional<FormProperty> formPropertie = formProperties.stream().filter(it -> it.getId().equals(String.valueOf(options.get("name")))).findFirst();
        if (formPropertie.isPresent()) {
            FormProperty formProperty = formPropertie.get();
            /**
             * isRequired：输入框中是否必填这个参数（必须的）
             * isWritable：用户提交表单时是否可以包含这个参数？（可写的）
             * isReadable：这个参数是否可以读取：在表单中显示，并可通过(可读的)
             * */
            // options.fluentPut("required", formProperty.isRequired());//是否必填
            options.fluentPut("hidden", false);//是否可见
            options.fluentPut("readonly", !formProperty.isWritable());//只读
            options.fluentPut("disabled", !formProperty.isWritable());//只读
            // 数据表格 data-table
            JSONArray operationButtons = options.getJSONArray("operationButtons");
            if (operationButtons != null && operationButtons.size() > 0) {//表格中的操作按钮
                for (int i = 0; i < operationButtons.size(); i++) {
                    JSONObject button = (JSONObject) operationButtons.get(i);
                    button.fluentPut("disabled", !formProperty.isWritable());//只读
                }
            }
        } else {
            options.fluentPut("hidden", true);//是否可见
        }
        if (options.get("readonly") == null) {
            // System.out.println("options = " + options);
        }
        System.out.println("字段：" + options.get("label") + "，是否必填：" + options.get("required") + "，是否可见：" + options.get("hidden") + "，只读：" + options.get("readonly"));
    }

    void subFormOptions(List<FormProperty> formProperties, JSONObject options, JSONArray childrenWidgetLists) {
        Optional<FormProperty> formPropertie = formProperties.stream().filter(it -> it.getId().equals(String.valueOf(options.get("name")))).findFirst();
        if (formPropertie.isPresent()) {
            FormProperty formProperty = formPropertie.get();
            /**
             * isRequired：输入框中是否必填这个参数（必须的）
             * isWritable：用户提交表单时是否可以包含这个参数？（可写的）
             * isReadable：这个参数是否可以读取：在表单中显示，并可通过(可读的)
             * */
            // options.fluentPut("required", formProperty.isRequired());//是否必填
            options.fluentPut("hidden", false);//是否可见
            options.fluentPut("readonly", !formProperty.isWritable());//只读
            // options.fluentPut("disabled", !formProperty.isWritable());//只读   一旦设置，里面的属性便不受控制
            // 如果是只读时，对下方的全部特殊处理
            if (!formProperty.isWritable()) {
                for (int i = 0; i < childrenWidgetLists.size(); i++) {
                    JSONObject childrenWidget = childrenWidgetLists.getJSONObject(i);
                    JSONObject childrenOptions = childrenWidget.getJSONObject("options");
                    String formFiledType = String.valueOf(childrenWidget.get("type"));
                    childrenOptions.fluentPut("hidden", false);//是否可见
                    childrenOptions.fluentPut("readonly", true);//只读
                    childrenOptions.fluentPut("disabled", true);//只读
                    System.out.println("子表单【" + options.get("label") + "】---字段：" + childrenOptions.get("label") + "，是否必填：" + childrenOptions.get("required") + "，是否可见：" + childrenOptions.get("hidden") + "，只读：" + childrenOptions.get("readonly"));
                }
            }
        } else {
            options.fluentPut("hidden", true);//是否可见
        }
        if (options.get("readonly") == null) {
            // System.out.println("options = " + options);
        }
        System.out.println("字段：" + options.get("label") + "，是否必填：" + options.get("required") + "，是否可见：" + options.get("hidden") + "，只读：" + options.get("readonly"));
    }

    @Override
    public List<FormProperty> findFormFieldByKey(String processDefinitionKey, String taskId) {
        List<FormProperty> formProperties = new ArrayList<>();
        if (StringUtil.isNotEmpty(taskId)) {//流程已经发起
            TaskService taskService = processEngine.getTaskService();
            Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
            if (task == null) {
                throw new BusinessRuntimeException("taskId存在异常");
            }
            FormService formService = processEngine.getFormService();
            TaskFormData formData = formService.getTaskFormData(taskId);
            formProperties = formData.getFormProperties();//流程中的表单属性
        } else {//流程尚未发起
            RepositoryService repositoryService = processEngine.getRepositoryService();
            FormService formService = processEngine.getFormService();
            List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery()
                    .processDefinitionKey(processDefinitionKey).orderByProcessDefinitionVersion().desc().list();
            if (list.size() == 0) {
                throw new BusinessRuntimeException("流程尚未发布，请检查...");
            }
            ProcessDefinition definition = list.get(0);
            String processDefinitionId = definition.getId();
            StartFormData formData = formService.getStartFormData(processDefinitionId);
            String formKey = formData.getFormKey();//表单key
            formProperties = formData.getFormProperties();//流程中的表单属性
            System.out.println("formProperties = " + formProperties);
        }
        return formProperties;
    }

}
